/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package neuralmusic.brain;

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import java.util.Vector;
import java.util.concurrent.DelayQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Timer;

import neuralmusic.brain.gui.DisplayableBrain;
import uk.co.drpj.util.tweaks.Tweakable;
import uk.co.drpj.util.tweaks.TweakableDouble;

/**
 * 
 * @author pjl
 */
public class Module2D implements Module, DisplayableBrain {

	public Vector<Tweakable> tweaks = new Vector<Tweakable>();

	List<Neuron> neurons = new ArrayList<Neuron>();
	List<Connection> connections = new ArrayList<Connection>();
	ArrayList<Neuron> greyMatter;
	// ArrayList<Neuron> outputs;
	ArrayList<Location> visible;
	Random rand = new Random();

	public DelayQueue<Neuron> fireQueue;

	// ArrayList<Connection> inputs; //TODO could be subset of conenctions ?

	final Thread fireThread;
	private long delayMax;

	double delaySum = 0.0;
	long fireCount;
	private int inStart;

	private int inEnd;
	protected int outStart;

	protected int outEnd;

	// private final TweakableDouble motorTimeConstant;


	Module2D() {


		greyMatter = new ArrayList<Neuron>();

		visible = new ArrayList<Location>();


		fireThread = new Thread(new Runnable() {

			@Override
			public void run() {
				while (true) {

					Neuron n;
					try {
						n = fireQueue.take();
						long d = n.getDelay(TimeRef.timeUnit);
						delayMax = Math.max(delayMax, d);
						delaySum += d;
						fireCount++;
						n.fire();
					} catch (InterruptedException ex) {
						Logger.getLogger(Module2D.class.getName()).log(
								Level.SEVERE, null, ex);
					}
				}
			}
		});

	}

	public void start() throws Exception {
		fireThread.start();
	}

	void setInputSlice(int inStart, int inSize) {
		this.inStart = inStart;
		this.inEnd = inStart + inSize;
	}

	void setOuputSlice(int outStart, int outSize) {
		this.outStart = outStart;
		this.outEnd = outStart + outSize;
	}

	

	public List<Location> getVisible() {

		return visible;
	}

	public List<Connection> getInputs() {

		return connections.subList(inStart, inEnd);
	}

	public List<Connection> getOutputs() {
		return connections.subList(outStart, outEnd);
	}

	public List<Neuron> getNeurons() {
		return neurons;
	}

	
//	@Override
//	public List<Connection> getConnections() {
//		return connections;
//	}

	public void createConnections(float[] weights) {
		int n = weights.length;
		for (int i = 0; i < n; i++) {
			connections.add(new Connection(weights[i], i));
		}

	}

	public void add(Neuron neuron) {
		neurons.add(neuron);
	}

	
}
